﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;
using CommunityServerRest;
using CSWriter.Blogs;
using CSWriter.Properties;
using Microsoft.WindowsMobile.Forms;


namespace CSWriter {
	public partial class Editor : Form {

		bool modified = false;

		bool publishAsNew;
		public bool PublishAsNew {
			get {
				return publishAsNew;
			}
			set {
				publishAsNew = value;
				if (value) {
					Text = Resources.ComposingNew;
					commitMenu.Text = Resources.Publish;
					btnChangeBlog.Visible = true;
				} else {
					Text = Resources.EditingPost;
					commitMenu.Text = Resources.SaveChanges;
					btnChangeBlog.Visible = false;
				}
			}
		}

		private Editor() {
			InitializeComponent();
		}
		public Editor(BlogManager manager, Settings settings) 
			: this() {
			Manager = manager;
			PublishAsNew = true;
			Settings = settings;
			Post = new BlogPostItem();
		}
		public Editor(BlogManager manager, BlogPostItem postToEdit, Settings settings, bool publishAsNew)
			: this(manager, settings) {
			PublishAsNew = publishAsNew;
			Post = postToEdit;
		}

		public BlogManager Manager { get; private set; }
		public Settings Settings { get; private set; }
		

		private Attachment Attachment {
			get {
				return post.Attachment;
			}
			set {
				post.Attachment = value;

				if (post.Attachment != null) {
					attachmentMsg.Text = string.Format(Resources.AttachmentContents, post.Attachment.Filename);

					removeAttachment.Visible = true;
					if (IsImage(post.Attachment.Filename)) {
						try {
							MemoryStream ms = new MemoryStream(post.Attachment.Contents);
							Bitmap bmp = new Bitmap(ms);
							pictureBox1.Image = bmp;
						} catch {
							pictureBox1.Image = Resources.InvalidImage;
						}
						imageOptions.Visible = true;
					} else {
						imageOptions.Visible = false;
					}

				} else {
					attachmentMsg.Text = Resources.NoAttachments + post.Attachment;
					removeAttachment.Visible = false;
					imageOptions.Visible = false;
				}
			}
		}

		public BlogPostItem post=new BlogPostItem();
		public BlogPostItem Post {
			get {
				return post;
			}
			private set {
				post = value;
				if (value != null) {
					títuloTextBox.Text = value.Title;
					cuerpoTextBox.Text = value.Body;
					if (value.Keywords.Keyword!=null)
						UpdateKeywordsList();

					Attachment = value.Attachment;
					if (PublishAsNew) {
						DestinationBlog = Settings.DefaultBlog;
					} 
				}
			}
		}

		private void UpdateKeywordsList() {
			lstKeywords.BeginUpdate();
			lstKeywords.Items.Clear();
			foreach (string k in post.Keywords.Keyword) {
				lstKeywords.Items.Add(k);
			}
			lstKeywords.EndUpdate();
		}

		private bool IsImage(string value) {
			bool found=false;
			int t = 0;
			string[] supportedExts = { ".jpg", ".gif", ".bmp", ".png" };
			while (!found && t<supportedExts.Length) {
				string ext = supportedExts[t];
				found=value.EndsWith(ext);
				t++;
			}
			return found;
		}
		private void browseAttachment_Click(object sender, EventArgs e) {
			OpenFileDialog openFileDialog = new OpenFileDialog();
			if (openFileDialog.ShowDialog() == DialogResult.OK) {
				Attachment = new Attachment(openFileDialog.SelectedFile);
			}
		}
		private void removeAttachment_Click(object sender, EventArgs e) {
			if (Attachment != null) {
				Attachment = null;
				modified = true;
			}
		}
		private void cerrar_Click(object sender, EventArgs e) {
			if (modified)
				AskForSave();
			DialogResult = DialogResult.Yes;
			Close();
		}
		private void AskForSave() {
			if (MessageBox.Show(Resources.DraftsQuestion, Resources.SaveChanges, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes) {
				string fileName;
				if (string.IsNullOrEmpty(Post.Title)) {
					fileName = Resources.Untitled + Settings.PostExtension;
				} else {
					fileName = Post.Title + Settings.PostExtension;
				}
				SaveLocalCopy(Settings.DraftsPath);
			}
		}
		private void EnsureFolderCreation(string folder) {
			if (!Directory.Exists(folder))
				Directory.CreateDirectory(folder);
		}
		private void publicar_Click(object sender, EventArgs e) {

			UpdatePostFields();



			if (post.BlogInfo == null) {
				MessageBox.Show(Resources.NoBlogSelected);
				SelectBlog select = new SelectBlog(Manager);
				if (select.ShowDialog() == DialogResult.OK) {
					post.BlogInfo = select.SelectedBlog;
				}
			}


			statusBar1.Visible = true;
			Enabled = false;

			if (PublishAsNew)
				statusBar1.Text = Resources.Publishing;
			else
				statusBar1.Text = Resources.Updating;

			Refresh();

			if (Settings.ImageOptions.Resample && post.Attachment != null)
				PreprocessAttachment(Post);

			try {
				BlogPostItem ret;
				if (PublishAsNew) {
					ret = CreateEntry();
				} else {
					ModifyEntry();
					ret = Post;
				}

				// Guarda el artículo creado
				string savedPath = SaveLocalCopy(Settings.PostsPath);

				if (publishAsNew) {
					MessageBox.Show(Resources.BlogPostPublished);
				} else {
					MessageBox.Show(Resources.BlogPostUpdated);
				}

				OnPostPublished(ret, savedPath);

				statusBar1.Visible = false;
				Enabled = true;
				Close();
			} catch (Exception ex) {
				if (PublishAsNew)
					MessageBox.Show(string.Format(Resources.CouldNotCreatePost, ex));
				else
					MessageBox.Show(string.Format(Resources.PostCannotBeModified, ex));
			}
		}

		private void ModifyEntry() {
			Manager.UpdatePost(Post);			
		}
		private BlogPostItem CreateEntry() {

			BlogPostItem createdPost;

			Post.Date = DateTime.Now;

			BlogPost ret=Manager.CreatePost(Post);

			createdPost = new BlogPostItem(ret);

			return createdPost;
		}
		private void PreprocessAttachment(BlogPostItem Artículo) {

			if (IsImage(Artículo.Attachment.Filename)) {
				using (MemoryStream ms = new MemoryStream(Artículo.Attachment.Contents)) {
					using (Bitmap bmp = new Bitmap(ms)) {
						Size oldSize = bmp.Size;
						Size newSize = new Size(Settings.ImageOptions.MaxWidth, Settings.ImageOptions.MaxHeight);
						Size resampleSize = RestrictSize(oldSize, newSize);
						
						Bitmap newBmp=new Bitmap(newSize.Width, newSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
						using (Graphics g = Graphics.FromImage(newBmp)) {
							Rectangle destRect = new Rectangle(0, 0, newSize.Width, newSize.Height);
							g.DrawImage(bmp, destRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, new ImageAttributes());
						}

						ms.Close();


						using (MemoryStream outputStream = new MemoryStream()) {
							newBmp.Save(outputStream, ImageFormat.Jpeg);
							outputStream.Position = 0;
							int length = (int)outputStream.Length;
							byte[] newContent = new byte[length];
							outputStream.Read(newContent, 0, length);
							Artículo.Attachment.Contents = newContent;
						}
					}
				}
			}
		}
		public Size RestrictSize(Size size, Size maxSize) {

			Size reescalado;

			//Hacemos regla de tres
			Size reescAncho = new Size(maxSize.Width, (size.Height * maxSize.Width) / size.Width);
			Size reescAlto = new Size((size.Width * maxSize.Height) / size.Height, maxSize.Height);

			if (reescAncho.Height > maxSize.Height)
				reescalado = reescAlto;
			else
				reescalado = reescAncho;
			return reescalado;
		}
		private string SaveLocalCopy(string path) {
			// Primero se asegura de que la carpeta está creada y lista
			EnsureFolderCreation(path);

			string resultingPath = Path.Combine(path, string.Concat(GenerateFileName(Post), Settings.PostExtension));
			Post.SaveTo(resultingPath);
			return resultingPath;
		}

		/// <summary>
		/// Este método genera un nombre de archivo válido para el artículo
		/// </summary>
		/// <param name="Artículo">El artículo a partir del que se generará el nombre</param>
		/// <returns></returns>
		private string GenerateFileName(BlogPostItem Artículo) {
			string filename = "";
			foreach (char c in Artículo.Title) {
				if (((short)c) > 31) {
					string toCheck=char.ToString(c);
					string nonValid="\"*/:<>?\\|";
					if (!nonValid.Contains(toCheck))
						filename=string.Concat(filename, toCheck);
				}
			}
			return filename;
		}
		private void OnPostPublished(BlogPostItem blogPost, string localCopyPath) {
			if (PostPublished != null) {
				PostPublished(this, blogPost, localCopyPath);
			}
		}
		public event PostPublishedEventHandler PostPublished;
		public delegate void PostPublishedEventHandler(object sender, BlogPostItem post, string localCopyPath);
		private void button2_Click(object sender, EventArgs e) {
			FileStream file=new FileStream(Path.Combine("\\", post.Attachment.Filename), FileMode.OpenOrCreate);
			file.Write(post.Attachment.Contents, 0, post.Attachment.Contents.Length);
		}
		private void inputPanel1_EnabledChanged(object sender, EventArgs e) {
			SuspendLayout();
			panelSIP.Visible = inputPanel1.Enabled;
			panelSIP.Height = inputPanel1.Bounds.Height;
			ResumeLayout();
		}
		private void button2_Click_1(object sender, EventArgs e) {
			ImageOptionsForm optionsForm = new ImageOptionsForm();
			optionsForm.ImageOptions = Settings.ImageOptions;
			if (optionsForm.ShowDialog() == DialogResult.OK) {
				Settings.ImageOptions = optionsForm.ImageOptions;
			}
		}
		private void capturePicture_Click(object sender, EventArgs e) {
			CameraCaptureDialog capDlg = new CameraCaptureDialog();
			capDlg.Mode = CameraCaptureMode.Still;
			if (capDlg.ShowDialog() == DialogResult.OK) {
				Cursor.Current = Cursors.WaitCursor;
				Attachment=new Attachment(capDlg.FileName);
				Cursor.Current = Cursors.Default;
				modified = true;
			}
		}
		private void button1_Click(object sender, EventArgs e) {
			contextMenu1.Show(button1, new Point(button1.Width, 0));
		}
		private void títuloTextBox_Validated(object sender, EventArgs e) {
			post.Title = títuloTextBox.Text;
		}

		private void cuerpoTextBox_Validated(object sender, EventArgs e) {
			post.Body = cuerpoTextBox.Text;
		}

		private void Editor_KeyDown(object sender, KeyEventArgs e) {
			if ((e.KeyCode == System.Windows.Forms.Keys.Up)) {
				// Up
			}
			if ((e.KeyCode == System.Windows.Forms.Keys.Down)) {
				// Down
			}
			if ((e.KeyCode == System.Windows.Forms.Keys.Left)) {
				// Left
			}
			if ((e.KeyCode == System.Windows.Forms.Keys.Right)) {
				// Right
			}
			if ((e.KeyCode == System.Windows.Forms.Keys.Enter)) {
				//publicar_Click(sender, EventArgs.Empty);
			}

		}

		private void UpdatePostFields() {
			post.Title = títuloTextBox.Text;
			post.Body = cuerpoTextBox.Text;
		}

		private void PostChanges(object sender, KeyPressEventArgs e) {
			modified = true;
		}

		private void Editor_Load(object sender, EventArgs e) {
			títuloTextBox.Focus();
		}

		private void btnAddKeyword(object sender, EventArgs e) {
			if (txtKeyword.Text.Trim().Length > 0) {
				post.Keywords.Keyword.Add(txtKeyword.Text);
				lstKeywords.Items.Add(txtKeyword.Text.Trim());
				txtKeyword.Text = string.Empty;
				txtKeyword.Focus();
			} else {
				MessageBox.Show(Resources.InvalidKeyword);
			}
		}

		private void btnChangeBlog_Click(object sender, EventArgs e) {
			SelectBlog selector = new SelectBlog(Manager);
			selector.SelectedBlog = post.BlogInfo;
			if (selector.ShowDialog() == DialogResult.OK)
				DestinationBlog = selector.SelectedBlog;
		}

		private BlogInfo destBlog;
		public BlogInfo DestinationBlog {
			get {
				return destBlog;
			}
			set {
				destBlog = value;
				if (value != null) {
					Blog blog = Manager.GetBlog(value.Id);
					if (PublishAsNew) {
						lblBlog.Text = string.Format(Resources.PublishToBlog, blog);
					} else {
						lblBlog.Text = string.Format(Resources.PublishedIn, blog);
					}
				} else {
					lblBlog.Text = string.Format(Resources.NoDestinationBlog);
				}
			}
		}

		private void menuDeleteKeyword_Click(object sender, EventArgs e) {
			string selected=(string) lstKeywords.SelectedItem;
			int id=lstKeywords.SelectedIndex;
			lstKeywords.Items.RemoveAt(id);
			post.Keywords.Keyword.Remove(selected);
		}

		private void menuKeyword_Popup(object sender, EventArgs e) {
			menuDeleteKeyword.Enabled = (lstKeywords.SelectedItem != null);
		}

		private void tabControl_SelectedIndexChanged(object sender, EventArgs e) {
			htmlPreview1.HtmlSource = cuerpoTextBox.Text;
		}
	}
}